﻿namespace Moly.IL
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text.RegularExpressions;
    using System.Xml;
    using Build;
    using Com;
    using misc;

    public class VSSolution : IProject
    {
        private readonly List<VSSProject> _projects;
        private readonly string _fileName;

        public VSSolution(string sln)
        {
            _fileName = sln;
            var lines = File.ReadAllLines(sln);
            var rx = new Regex("Project[^=]+=\\s+\"(.+)\",\\s+\"(.+)\",\\s+\"(.+)\"");
            _projects = new List<VSSProject>();
            foreach (var line in lines)
            {
                var m = rx.Match(line);
                if(!m.Success)
                    continue;

                var vssProject = new VSSProject(m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value);
                vssProject.Load(Path.GetDirectoryName(sln));

                _projects.Add(vssProject);
            }
            Assembly = Path.GetFileNameWithoutExtension(sln);
            Dependencies = new ModuleList();

            _projects.SelectMany(p => p.Dependencies.Where(dep => !Dependencies.Has(dep))).ToList().ForEach(d => Dependencies.Add(d));
        }

        public string ProjectDir
        {
            get { return Path.GetDirectoryName(_fileName); }
        }

        public string Assembly { get; private set; }
        
        public bool IsApplication
        {
            get
            {
                //VSS solutions are allways considred as application, no special versioning service is provided.
                return true;
            }
        }

        public ModuleList Dependencies { get; private set; }

        public DateTime ModificationDate
        {
            get
            {
                string file;
                return Utility.GetNewestDate(Path.GetDirectoryName(_fileName), "*.*", out file, "bin", "debug", "release", "obj", "user");
            }
        }

        public List<string> SrcFiles
        {
            get
            {
                return _projects.SelectMany(p => p.Files).ToList();
            }
        }

        public string BuildDir { get; set; }

        public string Dir
        {
            get { return Path.GetDirectoryName(_fileName);}
        }

        public void Compile(string lastBuild)
        {
            var nwSln = updateSolutionFile();
            try
            {
                _projects.ForEach(p => p.UpdateFile(Dependencies, BuildDir));


                var msbuild = @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe";

                var errorLevel = shellExecute(msbuild, nwSln);
                if (errorLevel != 0)
                    Console.Error.WriteLine("Build Failed for {0}", _fileName);

                Directory.CreateDirectory(BuildDir);
            }
            finally
            {
                if (File.Exists(nwSln))
                {
                    File.Delete(nwSln);
                }
                _projects.ForEach(p=>p.DeleteTempFiles());
            }
        }

        private int shellExecute(string msbuild, string nwSln)
        {
            throw new NotImplementedException();
        }

        private string updateSolutionFile()
        {
            var x = _fileName + ".sln";
            File.Copy(_fileName, x, true);
            return x;
        }

        public event Action<string> BeforEdit;
        public event Action<string> AfterEdit;
        public string GetPath()
        {
            return _fileName;
        }
    }

    public class VSSProject
    {
        private readonly string _name;
        private readonly string _relativePath;
        private readonly string _id;
        public readonly List<string> Files;
        public ModuleList Dependencies { get; private set; }

        public VSSProject(string name, string relativePath, string id)
        {
            _name = name;
            _relativePath = relativePath;
            _id = id;
            Files = new List<string>();
            Dependencies = new ModuleList();
        }

        public void Load(string slnDir)
        {
            var xdoc = new XmlDocument();
            xdoc.Load(Path.Combine(slnDir, _relativePath));
            var elems = xdoc.GetElementsByTagName("ItemGroup");

            foreach (XmlElement e in elems)
            {
                foreach(XmlNode node in e.ChildNodes)
                {
                    addNode(node);
                }
            }
        }

        private void addNode(XmlNode node)
        {
            if(!(node is XmlElement))
                return;

            var e = node as XmlElement;
            switch (e.Name)
            {
                case "Reference":
                    return;
                case "COMReference":
                    var desc = e.Attributes["Include"].Value;
                    var guid = e.ChildNodes[0].InnerText;
                    var vMaj = e.ChildNodes[1].InnerText;
                    var vMin = e.ChildNodes[2].InnerText;
                    var lcid = e.ChildNodes[3].InnerText;
                    Dependencies.Add(new ModuleID(guid, lcid, string.Format("{0}.dll", desc),
                                                      new BuildVersion(int.Parse(vMaj), int.Parse(vMin)), desc));
                    return;
                default:
                    if(e.Attributes["Include"] != null)
                        Files.Add(e.Attributes["Include"].Value);
                    
                        return;
            }
        }
        public override string ToString()
        {
            return string.Format("{0}:{1}", _name, _id);
        }

        public void DeleteTempFiles()
        {
            throw new NotImplementedException();
        }

        public void UpdateFile(ModuleList dependencies, string buildDir)
        {
            throw new NotImplementedException();
        }
    }
}